/*
 * @Autor: PK
 * @Date: 2021-03-31 13:34:14
 * @Description: 文件读取工具类
 */

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using ClosedXML.Excel;
using ExcelDataReader;

namespace ShkSimulation.core.util
{
    public class FileUtil{
        
        public static DataTable LoadExcel(string relativeFilePath, int sheet = 0, bool useHeaderRow = true) {
            if (relativeFilePath.EndsWith(".xml")) {
                return LoadXml(relativeFilePath, sheet, useHeaderRow);
            }
            DataSet ds = LoadExcelToDataSet(relativeFilePath, useHeaderRow);
            return ds?.Tables[sheet];
        }
        
        public static DataTable LoadXml(string relativeFilePath, int sheet = 0, bool useHeaderRow = true) {
            using FileStream stream = new FileStream(relativeFilePath, FileMode.Open, FileAccess.Read);
            DataSet dataSet = new DataSet();
            dataSet.ReadXml(relativeFilePath);
            return dataSet.Tables[sheet];
        }

        public static DataSet LoadExcelToDataSet(string relativeFilePath, bool useHeaderRow = true){
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            string filePath = Path.GetFullPath(relativeFilePath);
            if (!File.Exists(filePath)) {
                throw new FileNotFoundException("找不到文件！:" + relativeFilePath);
            }
            string extension = Path.GetExtension(filePath).ToLower();
            using FileStream stream = File.OpenRead(filePath);
            ExcelReaderConfiguration excelReaderConfiguration = new ExcelReaderConfiguration() {
                FallbackEncoding = Encoding.GetEncoding("GBK")
            };
            IExcelDataReader reader = extension switch {
                ".xls" => ExcelReaderFactory.CreateBinaryReader(stream, excelReaderConfiguration),
                ".xlsx" => ExcelReaderFactory.CreateOpenXmlReader(stream, excelReaderConfiguration),
                ".csv" => ExcelReaderFactory.CreateCsvReader(stream, excelReaderConfiguration),
                _ => null
            };
            if (reader == null)
                return null;
            ExcelDataSetConfiguration configuration = new ExcelDataSetConfiguration() {
                UseColumnDataType = true,
                ConfigureDataTable = (tableReader) => new ExcelDataTableConfiguration() {
                    UseHeaderRow = useHeaderRow,
                    // ReadHeaderRow = (rowReader) => {
                    //     rowReader.Read();
                    // },
                    FilterRow = (rowReader) => true,
                    FilterColumn = (rowReader, columnIndex) => true
                }
            };
            return reader.AsDataSet(configuration);
        }
        
        public static bool SaveDataTableToXml(DataTable dataTable, string relativeFilePath){
            if (dataTable == null || relativeFilePath == null) {
                return false;
            }
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            string filePath = Path.GetFullPath(relativeFilePath);
            if (File.Exists(filePath)) {
                File.Delete(filePath + ".backup");
                File.Move(filePath, filePath + ".backup");
            }
            using FileStream stream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write);
            XmlTextWriter xtr = new XmlTextWriter(stream, Encoding.GetEncoding("GBK"));
            xtr.Formatting = Formatting.Indented;
            xtr.WriteStartDocument();
            dataTable.WriteXml(xtr);
            return true;
        }
        
        public static bool SaveDataTableToExcel(DataTable dataTable, string relativeFilePath, string sheetName = "sheet", bool backup = false){
            if (dataTable == null || relativeFilePath == null) {
                return false;
            }
            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            string filePath = Path.GetFullPath(relativeFilePath);
            if (File.Exists(filePath)) {
                if (backup) {
                    File.Delete(filePath + ".backup");
                    File.Move(filePath, filePath + ".backup");
                } else {
                    File.Delete(filePath);
                }
            }
            using FileStream stream = new FileStream(filePath, FileMode.CreateNew, FileAccess.Write);
            XLWorkbook wb = new XLWorkbook();
            var worksheet = wb.AddWorksheet(dataTable, sheetName);
            worksheet.Columns().AdjustToContents();
            worksheet.Author = Environment.UserName;
            wb.Author = Environment.UserName;
            SaveOptions saveOptions = new SaveOptions();
            saveOptions.ConsolidateConditionalFormatRanges = true;
            saveOptions.EvaluateFormulasBeforeSaving = true;
            saveOptions.GenerateCalculationChain = true;
            wb.SaveAs(stream, saveOptions);
            wb.Dispose();
            return true;
        }        
        
        public static bool SaveDataTableToCsv(DataTable dataTable, string relativeFilePath){
            if (dataTable == null || relativeFilePath == null) {
                return false;
            }
            var lines = new List<string>();
            string[] columnNames = dataTable.Columns
                .Cast<DataColumn>()
                .Select(column => column.ColumnName)
                .ToArray();
            var header = string.Join(",", columnNames.Select(name => $"\"{name}\""));
            lines.Add(header);
            var valueLines = dataTable.AsEnumerable()
                .Select(row => string.Join(",", row.ItemArray.Select(val => $"\"{val}\"")));
            lines.AddRange(valueLines);
            File.WriteAllLines(relativeFilePath, lines, Encoding.GetEncoding("GBK"));
            return true;
        }
        
    }
}
